
function ClassPic(myDiagramDiv,myClassSavedModel) {

    var G = go.GraphObject.make;
    var myDiagram = {};
    var iscreateLink = false;
    var iscreateLinkType = 'generalization';

    this.initClassPic = function () {

        myDiagram =
            G(go.Diagram, myDiagramDiv,
                {
                    maxSelectionCount: 2,
                    allowDrop: true, // must be true to accept drops from the Palette
                    allowTextEdit: true,
                    allowHorizontalScroll: false,
                    allowVerticalScroll: false,
                    "undoManager.isEnabled": true,
                    // layout: G(go.,
                    //     { // this only lays out in trees nodes connected by "generalization" links
                    //         angle: 90,
                    //         path: go.TreeLayout.PathSource,  // links go from child to parent
                    //         setsPortSpot: false,  // keep Spot.AllSides for link connection spot
                    //         setsChildPortSpot: false,  // keep Spot.AllSides
                    //         // nodes not connected by "generalization" links are laid out horizontally
                    //         arrangement: go.TreeLayout.ArrangementHorizontal
                    //     })
                });


        // show visibility or access as a single character at the beginning of each property or method
        function convertVisibility(v) {
            switch (v) {
                case "public": return "+";
                case "private": return "-";
                case "protected": return "#";
                case "package": return "~";
                default: return v;
            }
        }

        // the item template for properties
        var propertyTemplate =
            G(go.Panel, "Horizontal",
                // property visibility/access
                G(go.TextBlock,
                    { isMultiline: false, editable: false, width: 12 },
                    new go.Binding("text", "visibility", convertVisibility)),
                // property name, underlined if scope=="class" to indicate static property
                G(go.TextBlock,
                    { isMultiline: false, editable: true },
                    new go.Binding("text", "name").makeTwoWay(),
                    new go.Binding("isUnderline", "scope", function(s) { return s[0] === 'c' })),
                // property type, if known
                G(go.TextBlock, "",
                    new go.Binding("text", "type", function(t) { return (t ? ": " : ""); })),
                G(go.TextBlock,
                    { isMultiline: false, editable: true },
                    new go.Binding("text", "type").makeTwoWay()),
                // property default value, if any
                G(go.TextBlock,
                    { isMultiline: false, editable: false },
                    new go.Binding("text", "default", function(s) { return s ? " = " + s : ""; }))
            ); 

        // the item template for methods
        var methodTemplate =
            G(go.Panel, "Horizontal",
                // method visibility/access
                G(go.TextBlock,
                    { isMultiline: false, editable: false, width: 12 },
                    new go.Binding("text", "visibility", convertVisibility)),
                // method name, underlined if scope=="class" to indicate static method
                G(go.TextBlock,
                    { isMultiline: false, editable: true },
                    new go.Binding("text", "name").makeTwoWay(),
                    new go.Binding("isUnderline", "scope", function(s) { return s[0] === 'c' })),
                // method parameters
                G(go.TextBlock, "()",
                    // this does not permit adding/editing/removing of parameters via inplace edits
                    new go.Binding("text", "parameters", function(parr) {
                        var s = "(";
                        for (var i = 0; i < parr.length; i++) {
                            var param = parr[i];
                            if (i > 0) s += ", ";
                            s += param.name + ": " + param.type;
                        }
                        return s + ")";
                    })),
                // method return type, if any
                G(go.TextBlock, "",
                    new go.Binding("text", "type", function(t) { return (t ? ": " : ""); })),
                G(go.TextBlock,
                    { isMultiline: false, editable: true },
                    new go.Binding("text", "type").makeTwoWay())
            );

        // this simple template does not have any buttons to permit adding or
        // removing properties or methods, but it could!
        myDiagram.nodeTemplate =
            G(go.Node, "Auto",
                [
                    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                    {
                        locationSpot: go.Spot.Center,
                    }
                ],
                G(go.Shape, { fill: "lightyellow" }),
                G(go.Panel, "Table",
                    { defaultRowSeparatorStroke: "black" },
                    {
                        contextMenu: makePartContextMenu()
                    },
                    // header
                    G(go.TextBlock,
                        {
                            row: 0, columnSpan: 2, margin: 3, alignment: go.Spot.Center,
                            font: "bold 12pt sans-serif",
                            isMultiline: false, editable: true
                        },
                        new go.Binding("text", "name").makeTwoWay()),
                    // properties
                    G(go.TextBlock, "Properties",
                        { row: 1, font: "italic 10pt sans-serif" },
                        new go.Binding("visible", "visible", function(v) { return !v; }).ofObject("PROPERTIES")),
                    G(go.Panel, "Vertical", { name: "PROPERTIES" },
                        new go.Binding("itemArray", "properties"),
                        {
                            row: 1, margin: 3, stretch: go.GraphObject.Fill,
                            defaultAlignment: go.Spot.Left, background: "lightyellow",
                            itemTemplate: propertyTemplate
                        }
                    ),
                    G("PanelExpanderButton", "PROPERTIES",
                        { row: 1, column: 1, alignment: go.Spot.TopRight, visible: false },
                        new go.Binding("visible", "properties", function(arr) { return arr.length > 0; })),
                    // methods
                    G(go.TextBlock, "Methods",
                        { row: 2, font: "italic 10pt sans-serif" },
                        new go.Binding("visible", "visible", function(v) { return !v; }).ofObject("METHODS")),
                    G(go.Panel, "Vertical", { name: "METHODS" },
                        new go.Binding("itemArray", "methods"),
                        {
                            row: 2, margin: 3, stretch: go.GraphObject.Fill,
                            defaultAlignment: go.Spot.Left, background: "lightyellow",
                            itemTemplate: methodTemplate
                        }
                    ),
                    G("PanelExpanderButton", "METHODS",
                        { row: 2, column: 1, alignment: go.Spot.TopRight, visible: false },
                        new go.Binding("visible", "methods", function(arr) { return arr.length > 0; })
                    ),

                )
            );

        function convertIsTreeLink(r) {
            return r === "generalization";
        }

        function convertFromArrow(r) {
            switch (r) {
                case "generalization": return "";
                default: return "";
            }
        }

        function convertToArrow(r) {
            switch (r) {
                case "generalization": return "Triangle";
                case "aggregation": return "StretchedDiamond";
                default: return "";
            }
        }

        myDiagram.linkTemplate =
            G(go.Link,
                { routing: go.Link.Orthogonal },
                new go.Binding("isLayoutPositioned", "relationship", convertIsTreeLink),
                G(go.Shape),
                G(go.Shape, { scale: 1.3, fill: "white" },
                    new go.Binding("fromArrow", "relationship", convertFromArrow)),
                G(go.Shape, { scale: 1.3, fill: "white" },
                    new go.Binding("toArrow", "relationship", convertToArrow))
            );


        myDiagram.addDiagramListener("ObjectSingleClicked", onObjectSingleClicked);
        var key1 = 0;
        var key2 = 0;

        function onObjectSingleClicked(ev) {
            var part = ev.subject.part;
            var key = part.data.key;
            if(iscreateLink){
                if(key1 == 0){
                    key1 = key;
                }else if(key1 != 0 && key2 == 0){
                    key2 = key;
                    var jsonNewStep = {
                        from: key1,
                        to: key2,
                        relationship: iscreateLinkType
                    };
                    myDiagram.model.addLinkData(jsonNewStep);
                    key1 = 0;
                    key2 = 0;
                    iscreateLink = false;
                }
            }
        };

        //加载类先
        this.loadClass();
    };

    this.createLink = function() {
        if(!iscreateLink){
            //创建关联
            iscreateLink = true;
            $('#addClassLinkDialog').modal({backdrop: 'static', keyboard: false});
        }
    };

    // 关闭弹框， 获取输入值，然后执行逻辑
    $("#ClassLinkDiv").click(function (){
        $("#addClassLinkDialog").modal("hide");
        var oBtn = document.getElementById("classLinkSelect");

        iscreateLinkType = oBtn.options[oBtn.selectedIndex].value
    });
    $("#ClassLinkBack").click(function (){
        $("#addClassLinkDialog").modal("hide");
        iscreateLink = false;
    });

    /**
     * 创建新步骤
     */
    this.createStep = function(jsonNewStep) {
		console.log(jsonNewStep);
        myDiagram.model.addNodeData(jsonNewStep);
    };

    //修改数据
    function showEditNode(node){
        node.data.text;
        console.log(node.data);
        //数据获取

    }

    /**
     * 右键菜单
     * @returns {*}
     */
    function makePartContextMenu(){
        return G(go.Adornment, "Vertical",
            makeMenuItem("编辑",
                function(e, obj) {
                    var contextmenu = obj.part;
                    var part = contextmenu.adornedPart;
                    showEditNode(part);
                }),
            makeMenuItem("删除",
                function(e, obj) { e.diagram.commandHandler.deleteSelection(); },
                function(o) { return o.diagram.commandHandler.canDeleteSelection(); })
        );
    };

    /**
     * 生成右键菜单项
     * @param text
     * @param action
     * @param visiblePredicate
     * @returns {*}
     */
    function makeMenuItem(text, action, visiblePredicate) {
        return G("ContextMenuButton",
            G(go.TextBlock, text, {
                margin: 5,
                textAlign: "left",
                stroke: "#555555"
            }),
            { click: action },
            // don't bother with binding GraphObject.visible if there's no predicate
            visiblePredicate ? new go.Binding("visible", "", visiblePredicate).ofObject() : {});
    };


    //保存
    this.saveClass = function() {
        myDiagram.isModified = false;
        return myDiagram.model.toJson();
    };

    //加载
    this.loadClass = function() {
        myDiagram.model = go.Model.fromJson(myClassSavedModel.value);
    };

    /**
     * 生成GUID
     * @returns {string}
     */
    function guid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    return this;
}
